package de.koller.aframe.util.math;

import Jama.Matrix;
import de.koller.oceanFramework.OceanException;
import de.koller.oceanFramework.math.RVec3;

public class BasicMatrixOp {

	public static RVec3 normalMap( RVec3 surfaceNormal, RVec3 bumpMapValue ) {
		throw new IllegalArgumentException();
	}
	
	public static RVec3 multiply( RVec3 v, Matrix m ) {
		if( m.getColumnDimension() == 3 ) {
			Matrix vm = new Matrix( new double[][] {
				{ v.x },
				{ v.y },
				{ v.z },
			} );

			Matrix r = m.times( vm );
			return new RVec3( (float)r.get( 0, 0 ), (float)r.get( 1, 0 ), (float)r.get( 2, 0 ) );
		} else if( m.getColumnDimension() == 4 ) {
			Matrix vm = new Matrix( new double[][] {
				{ v.x },
				{ v.y },
				{ v.z },
				{ 1 }
			} );

			Matrix r = m.times( vm );
			return new RVec3( (float)r.get( 0, 0 ), (float)r.get( 1, 0 ), (float)r.get( 2, 0 ) );
		} else
			throw new OceanException( "dimensions wrong!" );
	}
	
	public static Matrix createIMatrix( int size ) {
		Matrix m = new Matrix( size, size );
		for( int i = 0; i < size; i++ )
			m.set( i, i, 1 );
		return m;
	}
	
	public static Matrix createXRotation( double rot ) {
		Matrix m = new Matrix( new double[][] {
			{  1, 0, 0 },
			{ 0,  Math.cos( rot ), -Math.sin( rot ) },
			{ 0,  Math.sin( rot ),  Math.cos( rot ) },
		} );
		return m;
	}
	
	public static Matrix createYRotation( double rot ) {
		Matrix m = new Matrix( new double[][] {
			{  Math.cos( rot ), 0, Math.sin( rot ) },
			{  0, 1, 0 },
			{ -Math.sin( rot ), 0, Math.cos( rot ) },
		} );
		return m;
	}
	
	public static Matrix createZRotation( double rot ) {
		Matrix m = new Matrix( new double[][] {
			{  Math.cos( rot ), -Math.sin( rot ), 0 },
			{  Math.sin( rot ),  Math.cos( rot ), 0 },
			{  0, 0, 1 }
		} );
		return m;
	}
	
	public static Matrix createPerspective( double fovy, double aspect, double zNear, double zFar ) {
		double f = 1d / Math.tan( Math.toRadians( fovy ) / 2d );
		Matrix m = new Matrix( new double[][] {
			{ f / aspect, 0, 0, 0 },
			{ 0, f, 0, 0 },
			{ 0, 0, (zFar+zNear) / (zNear-zFar), (2d*zFar*zNear) / (zNear-zFar) },
			{ 0, 0, -1, 0 }
		} );
		return m;
	}
	
	public static Matrix createTranslation( double x, double y, double z ) {
		Matrix m = new Matrix( new double[][] {
			{ 1, 0, 0, x },
			{ 0, 1, 0, y },
			{ 0, 0, 1, z },
			{ 0, 0, 0, 1 }
		} );
		return m;
	}
	
	public static Matrix createLookAt( float eyeX,    float eyeY,    float eyeZ,
									   float centerX, float centerY, float centerZ,
									   float upX,     float upY,     float upZ ) {
		RVec3 f = new RVec3( centerX - eyeX, centerY - eyeY, centerZ - eyeZ ).normalize();
		RVec3 u = new RVec3( upX, upY, upZ ).normalize();
		RVec3 s = RVec3.cross( f, u ).normalize();
		
		Matrix m = new Matrix( new double[][] {
			{  s.x,  s.y,  s.z, 0 },
			{  u.x,  u.y,  u.z, 0 },
			{ -f.x, -f.y, -f.z, 0 },
			{    0,    0,    0, 1 }
		} );
		
		return m.times( createTranslation( eyeX, eyeY, eyeZ ) );
	}
	
	public static void main( String[] args ) {
		Matrix m = createZRotation( Math.PI / 2f );
		RVec3 v = multiply( new RVec3( 1, 0, 0 ), m );
		System.out.println( v );
	}
	
}
